
package org.argetr.resim.ui.parts;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;

import org.argetr.resim.ShapesPlugin;
import org.argetr.resim.ui.graphics.IconFigure;
import org.argetr.resim.ui.model.ComponentItem;
import org.argetr.resim.ui.model.Connection;
import org.argetr.resim.ui.model.ModelElement;
import org.argetr.resim.ui.model.Shape;
import org.argetr.resim.ui.model.commands.ConnectionCreateCommand;
import org.argetr.resim.ui.model.commands.ConnectionReconnectCommand;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;

import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.DropRequest;
import org.eclipse.gef.requests.ReconnectRequest;

import org.eclipse.swt.graphics.Image;


/**
 * EditPart used for Shape instances (more specific for EllipticalShape and
 * RectangularShape instances).
 * <p>
 * This edit part must implement the PropertyChangeListener interface, so it can
 * be notified of property changes in the corresponding model element.
 * </p>
 * 
 * @author Elias Volanakis
 */
class ShapeEditPart extends AbstractGraphicalEditPart implements
		PropertyChangeListener, NodeEditPart {

	/**
	 * Upon activation, attach to the model element as a property change
	 * listener.
	 */
	public ShapeEditPart() {
		super();
	}

	public void activate() {
		if (!isActive()) {
			super.activate();
			((ModelElement) getModel()).addPropertyChangeListener(this);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.editparts.AbstractEditPart#createEditPolicies()
	 */
	protected void createEditPolicies() {
		// allow removal of the associated model element
		installEditPolicy(EditPolicy.COMPONENT_ROLE,
				new ShapeComponentEditPolicy());
		// allow the creation of connections and
		// and the reconnection of connections between Shape instances
		installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE,
				new GraphicalNodeEditPolicy() {
					/*
					 * (non-Javadoc)
					 * 
					 * @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#getConnectionCompleteCommand(org.eclipse.gef.requests.CreateConnectionRequest)
					 */
					protected Command getConnectionCompleteCommand(
							CreateConnectionRequest request) {
						ConnectionCreateCommand cmd = (ConnectionCreateCommand) request
								.getStartCommand();
						cmd.setTarget((Shape) getHost().getModel());
						return cmd;
					}

					/*
					 * (non-Javadoc)
					 * 
					 * @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#getConnectionCreateCommand(org.eclipse.gef.requests.CreateConnectionRequest)
					 */
					protected Command getConnectionCreateCommand(
							CreateConnectionRequest request) {
						Shape source = (Shape) getHost().getModel();
						int style = ((Integer) request.getNewObjectType())
								.intValue();
						ConnectionCreateCommand cmd = new ConnectionCreateCommand(
								source, style);
						request.setStartCommand(cmd);
						return cmd;
					}

					/*
					 * (non-Javadoc)
					 * 
					 * @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#getReconnectSourceCommand(org.eclipse.gef.requests.ReconnectRequest)
					 */
					protected Command getReconnectSourceCommand(
							ReconnectRequest request) {
						Connection conn = (Connection) request
								.getConnectionEditPart().getModel();
						Shape newSource = (Shape) getHost().getModel();
						ConnectionReconnectCommand cmd = new ConnectionReconnectCommand(
								conn);
						cmd.setNewSource(newSource);
						return cmd;
					}

					/*
					 * (non-Javadoc)
					 * 
					 * @see org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy#getReconnectTargetCommand(org.eclipse.gef.requests.ReconnectRequest)
					 */
					protected Command getReconnectTargetCommand(
							ReconnectRequest request) {
						Connection conn = (Connection) request
								.getConnectionEditPart().getModel();
						Shape newTarget = (Shape) getHost().getModel();
						ConnectionReconnectCommand cmd = new ConnectionReconnectCommand(
								conn);
						cmd.setNewTarget(newTarget);
						return cmd;
					}
				});
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#createFigure()
	 */
	protected IFigure createFigure() {
		IFigure f = createFigureForModel();
		f.setOpaque(true); // non-transparent figure
		f.setBackgroundColor(ColorConstants.titleGradient);
		return f;
	}

	/**
	 * Return a IFigure depending on the instance of the current model element.
	 * This allows this EditPart to be used for both sublasses of Shape.
	 */
	private IFigure createFigureForModel() {
		ComponentItem ci = ComponentItem.class.cast(getModel());
		if (ci != null) {
			Image icon = ShapesPlugin.getImageDescriptor("icons/org.argetr.resim.proc.jpg")
					.createImage();
			String name = ((ComponentItem) getModel()).GetName();
			return new IconFigure(icon, name, ci);
			/*
			 * RoundedRectangle rr = new RoundedRectangle();
			 * rr.setCornerDimensions(new Dimension(10, 10)); return rr;
			 */
			// return new Ellipse();
		}
		/*
		 * if (getModel() instanceof EllipticalShape) { RoundedRectangle rr =
		 * new RoundedRectangle(); rr.setCornerDimensions(new Dimension(10,
		 * 10)); return rr; // return new Ellipse(); } else if (getModel()
		 * instanceof RectangularShape) { return new RectangleFigure(); }
		 */else {
			// if Shapes gets extended the conditions above must be updated
			throw new IllegalArgumentException();
		}
	}

	/**
	 * Upon deactivation, detach from the model element as a property change
	 * listener.
	 */
	public void deactivate() {
		if (isActive()) {
			super.deactivate();
			((ModelElement) getModel()).removePropertyChangeListener(this);
		}
	}

	private Shape getCastedModel() {
		return (Shape) getModel();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getModelSourceConnections()
	 */
	protected List<Connection> getModelSourceConnections() {
		//System.out.println("ShapeEditPart.getMOdelSourceConnections");
		return getCastedModel().getSourceConnections();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getModelTargetConnections()
	 */
	protected List<Connection> getModelTargetConnections() {
		return getCastedModel().getTargetConnections();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.NodeEditPart#getSourceConnectionAnchor(org.eclipse.gef.ConnectionEditPart)
	 */
	public ConnectionAnchor getSourceConnectionAnchor(
			ConnectionEditPart connection) {
		//System.out
			//	.println("ShapeEditPart.getSourceConnectionAnchor(ConnectionEditPart connection) ");
		ComponentItem ci = (ComponentItem) getModel();
		Connection conn = (Connection) connection.getModel();
		int srcIndex = conn.getSrcIndex();
		//System.out
			//	.println("ShapeEditPart.getSourceConnectionAnchor->srcIndex = "
					//	+ conn.getSrcIndex());
		if (srcIndex >= 0) {
			Connection.CANDIDATE_SRC_INDEX = srcIndex;
		}else{
			
		}
		InOutAnchor anc = new InOutAnchor(getFigure(), ci, true, true);
		//System.out.println("ShapeEditPart.getSourceConnectionAnchor->"
			//	+ "Connection.CANDIDATE_SRC_INDEX = "
			//	+ Connection.CANDIDATE_SRC_INDEX);
		anc.setPinIndex(Connection.CANDIDATE_SRC_INDEX);
		return anc;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.NodeEditPart#getSourceConnectionAnchor(org.eclipse.gef.Request)
	 */
	public ConnectionAnchor getSourceConnectionAnchor(Request request) {
		//System.out
				//.println(" ShapeEditPart.getSourceConnectionAnchor(Request request)");
		Point pt = new Point(((DropRequest) request).getLocation());
		ComponentItem ci = (ComponentItem) getModel();
		InOutAnchor anc = new InOutAnchor(getFigure(), ci, true, false);
		anc.setMouseLocation(pt);
		return anc;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.NodeEditPart#getTargetConnectionAnchor(org.eclipse.gef.ConnectionEditPart)
	 */
	public ConnectionAnchor getTargetConnectionAnchor(
			ConnectionEditPart connection) {
		//System.out
			//	.println("ShapeEditPart.getTargetConnectionAnchor(ConnectionEditPart connection)");
		Connection conn = (Connection) connection.getModel();
		ComponentItem ci = (ComponentItem) getModel();
		int dstIndex = conn.getDstIndex();
		//System.out
			//	.println("ShapeEditPart.getSourceConnectionAnchor->dstIndex = "
					//	+ conn.getDstIndex());
		if (dstIndex >= 0) {
			Connection.CANDIDATE_DST_INDEX = dstIndex;
		}

		InOutAnchor anc = new InOutAnchor(getFigure(), ci, false, true);
		anc.setPinIndex(Connection.CANDIDATE_DST_INDEX);
		//System.out
				//.println("ShapeEditPart.getTargetConnectionAnchor(ConnectionEditPart connection)->"
					//	+ "Connection.CANDIDATE_DST_INDEX = "
					//	+ Connection.CANDIDATE_DST_INDEX);
		return anc;
		// return getConnectionAnchor();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.NodeEditPart#getTargetConnectionAnchor(org.eclipse.gef.Request)
	 */
	public ConnectionAnchor getTargetConnectionAnchor(Request request) {

		//System.out
				//.println("ShapeEditPart.getTargetConnectionAnchor(Request request)");
		Point pt = new Point(((DropRequest) request).getLocation());
		ComponentItem ci = (ComponentItem) getModel();
		InOutAnchor anc = new InOutAnchor(getFigure(), ci, false, false);
		anc.setMouseLocation(pt);
		return anc;
		// return getConnectionAnchor();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
	 */
	public void propertyChange(PropertyChangeEvent evt) {
		String prop = evt.getPropertyName();
		if (/* Shape.SIZE_PROP.equals(prop) || */Shape.LOCATION_PROP
				.equals(prop)) {
			refreshVisuals();
		} else if (Shape.SOURCE_CONNECTIONS_PROP.equals(prop)) {
			refreshSourceConnections();
		} else if (Shape.TARGET_CONNECTIONS_PROP.equals(prop)) {
			refreshTargetConnections();
		}
	}

	protected void refreshVisuals() {
		// notify parent container of changed position & location
		// if this line is removed, the XYLayoutManager used by the parent
		// container
		// (the Figure of the ShapesDiagramEditPart), will not know the bounds
		// of this figure
		// and will not draw it correctly.
		Rectangle bounds = new Rectangle(getCastedModel().getLocation(),
				getCastedModel().getSize());
		((GraphicalEditPart) getParent()).setLayoutConstraint(this,
				getFigure(), bounds);
	}
}